#!/usr/bin/env python
#
# email_setup.py
#
# Version : 0.7
# Date : 20080520
#
# Author : Bernard Czenkusz
# Email  : bernie@skipole.co.uk

# email_setup.py - Displays email setup panel and is a module in sm_gui
# package, run as part of the skipolemonitor gui interface
#
# Copyright (c) 2007 Bernard Czenkusz
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#

""" This is a module in the sm_gui package, and defines the Email setup panel

It is run as part of the skipolemonitor gui interface.
"""

import wx
import smtplib
import time
import socket
import validate

from net import *


class EmailSetup(wx.Panel):
    """The EmailSetup Panel which is used by one of the tabs, in the SetupNotebook Window"""
    #
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        #
        # Create the email sizer, splitting the Panel vertically
        self.email_sizer=wx.BoxSizer(wx.VERTICAL)
        #
        # Create the input fields and text in a grid sizer
        self.fields_sizer=wx.FlexGridSizer(rows=0, cols=2, hgap=20, vgap=20)
        button_size = (100,40)
        #
        # Email enable
        self.email_enable_field = wx.CheckBox(self, -1, "")
        self.fields_sizer.Add(self.email_enable_field, 0, wx.ALIGN_RIGHT)
        if net_cfg["EMAIL_ENABLED"]=="0":
            self.email_enable_field.SetValue(0)
        else:
            self.email_enable_field.SetValue(1)
        email_enable_text=wx.StaticText(self, -1,
             "Globally enable email : If unchecked, no mail will\nbe sent, regardless of group or host settings")
        self.fields_sizer.Add(email_enable_text, 0, wx.ALIGN_LEFT)
        #
        # Email max rate
        self.email_max_rate_field = wx.TextCtrl(self, -1, net_cfg["EMAIL_MAX_RATE"], size=(50,-1))
        self.email_max_rate_field.SetToolTipString("Limit the number of Alert Emails")
        self.fields_sizer.Add(self.email_max_rate_field, 0, wx.ALIGN_RIGHT)
        email_max_rate_text=wx.StaticText(self, -1,
            "Set the maximum number of alert emails in\nany 24 hours - default 50, 300 maximum.")
        self.fields_sizer.Add(email_max_rate_text, 0, wx.ALIGN_LEFT)
        #
        # Email source address
        self.email_source_address_field = wx.TextCtrl(self, -1, net_cfg["EMAIL_SOURCE"], size=(200,-1))
        self.email_source_address_field.SetToolTipString("From: Address")
        self.fields_sizer.Add(self.email_source_address_field, 0, wx.ALIGN_RIGHT)
        email_source_address_text=wx.StaticText(self, -1, "Set the source address of the email alerts.")
        self.fields_sizer.Add(email_source_address_text, 0, wx.ALIGN_LEFT)
        #
        # Email destination address
        self.email_destination_address_field = wx.TextCtrl(self, -1, net_cfg["EMAIL_DESTINATION"], size=(200,-1))
        self.email_destination_address_field.SetToolTipString("To: Address")
        self.fields_sizer.Add(self.email_destination_address_field, 0, wx.ALIGN_RIGHT)
        email_destination_address_text=wx.StaticText(self, -1,
           "Set destination address(es) to send alerts,\nseparated by semi-colons(;)")
        self.fields_sizer.Add(email_destination_address_text, 0, wx.ALIGN_LEFT)
        #
        # Email subject
        self.email_subject_field = wx.TextCtrl(self, -1, net_cfg["EMAIL_SUBJECT"], size=(200,-1))
        self.email_subject_field.SetToolTipString("Email subject text")
        self.fields_sizer.Add(self.email_subject_field, 0, wx.ALIGN_RIGHT)
        email_subject_text=wx.StaticText(self, -1,
           "Type text to appear in the email subject field")
        self.fields_sizer.Add(email_subject_text, 0, wx.ALIGN_LEFT)
        #
        # SMTP server
        self.smtp_server_field = wx.TextCtrl(self, -1, net_cfg["SMTP_SERVER"], size=(200,-1))
        self.smtp_server_field.SetToolTipString("SMTP server")
        self.fields_sizer.Add(self.smtp_server_field, 0, wx.ALIGN_RIGHT)
        smtp_server_text=wx.StaticText(self, -1, "The SMTP server which relays emails.")
        self.fields_sizer.Add(smtp_server_text, 0, wx.ALIGN_LEFT)
        #
        # Make column 1 growable - this allows the right descriptions to be large
        self.fields_sizer.AddGrowableCol(1,0)
        #
        # Add grid fields_sizer to the main sizer
        self.email_sizer.Add(self.fields_sizer, 0, wx.ALL | wx.ALIGN_CENTER, 40)
        #
        # -- Apply - Cancel - Test -- buttons
        #
        # Create a horizontal button_sizer to hold the buttons
        self.button_sizer=wx.BoxSizer(wx.HORIZONTAL)
        #
        # Apply button
        self.apply_button = wx.Button(self, wx.ID_APPLY, size=button_size)
        self.apply_button.Enable(False)
        self.apply_button.SetToolTipString("Click to apply changes.")
        self.button_sizer.Add(self.apply_button, 0, wx.ALL | wx.ALIGN_CENTER, 10)
        #
        # Cancel button
        self.cancel_button = wx.Button(self, wx.ID_CANCEL, size=button_size)
        self.cancel_button.Enable(False)
        self.cancel_button.SetToolTipString("Click to cancel changes.")
        self.button_sizer.Add(self.cancel_button, 0, wx.ALL | wx.ALIGN_CENTER, 10)
        #
        # Test button
        self.test_button = wx.Button(self, label="&Test", size=button_size)
        self.test_button.SetToolTipString("Click to send test email.")
        self.button_sizer.Add(self.test_button, 0, wx.ALL | wx.ALIGN_CENTER, 10)
        if net_cfg["EMAIL_ENABLED"]=="0":
            self.test_button.Enable(False)
        #
        #
        # Add button_sizer to the main sizer
        self.email_sizer.Add(self.button_sizer, 0, wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER, 40)
        #
        # Create test results box
        results_text="On pressing Test, an email will be sent"
        if net_cfg["EMAIL_ENABLED"]=="0":
            results_text="Emails are disabled, until the Global enable email checkbox is ticked - and the Apply button pressed."
        else:
            results_text="On pressing Test, an email will be sent"
        self.results_box=wx.StaticText(self, -1, results_text, size=(400,50), style=wx.ST_NO_AUTORESIZE)
        self.results_box.SetBackgroundColour('White')
        #
        # Add the results_box to the main sizer
        self.email_sizer.Add(self.results_box, 0, wx.ALL | wx.ALIGN_CENTER, 40)
        #
        # Set the size to the panel
        self.SetSizer(self.email_sizer)
        #
        # Bind the fields
        self.Bind(wx.EVT_CHECKBOX, self.email_enable, self.email_enable_field)
        self.Bind(wx.EVT_TEXT, self.email_max_rate, self.email_max_rate_field)
        self.Bind(wx.EVT_TEXT, self.email_source_address, self.email_source_address_field)
        self.Bind(wx.EVT_TEXT, self.email_destination_address, self.email_destination_address_field)
        self.Bind(wx.EVT_TEXT, self.email_subject, self.email_subject_field)
        self.Bind(wx.EVT_TEXT, self.smtp_server, self.smtp_server_field)
        #
        # Bind the buttons
        self.Bind(wx.EVT_BUTTON, self.apply_button_pressed, self.apply_button)
        self.Bind(wx.EVT_BUTTON, self.cancel_button_pressed, self.cancel_button)
        self.Bind(wx.EVT_BUTTON, self.test_button_pressed, self.test_button)


    # Email field binding methods, - enable Apply and Cancel buttons,
    # Disable Test button,  and initial check of input length

    def email_enable(self, event):
        """Email Enable checkbox toggled"""
        self.apply_button.Enable(True)
        self.cancel_button.Enable(True)
        self.test_button.Enable(False)
        return

    def email_max_rate(self, event):
        """Limit email max rate to three characters"""
        self.apply_button.Enable(True)
        self.cancel_button.Enable(True)
        self.test_button.Enable(False)
        text = event.GetString()
        if len(text)>3:
            pos=self.email_max_rate_field.GetInsertionPoint()
            self.email_max_rate_field.Remove(3,len(text)+1)
            self.email_max_rate_field.SetInsertionPoint(pos)

    def email_source_address(self, event):
        """Limit email source address to 50 characters"""
        self.apply_button.Enable(True)
        self.cancel_button.Enable(True)
        self.test_button.Enable(False)
        text = event.GetString()
        if len(text)>50:
            pos=self.email_source_address_field.GetInsertionPoint()
            self.email_source_address_field.Remove(50,len(text)+1)
            self.email_source_address_field.SetInsertionPoint(pos)

    def email_destination_address(self, event):
        """Limit email destination address to 250 characters"""
        self.apply_button.Enable(True)
        self.cancel_button.Enable(True)
        self.test_button.Enable(False)
        text = event.GetString()
        if len(text)>250:
            pos=self.email_destination_address_field.GetInsertionPoint()
            self.email_destination_address_field.Remove(250,len(text)+1)
            self.email_destination_address_field.SetInsertionPoint(pos)

    def email_subject(self, event):
        """Limit email subject to 250 characters"""
        self.apply_button.Enable(True)
        self.cancel_button.Enable(True)
        self.test_button.Enable(False)
        text = event.GetString()
        if len(text)>250:
            pos=self.email_subject_field.GetInsertionPoint()
            self.email_subject_field.Remove(250,len(text)+1)
            self.email_subject_field.SetInsertionPoint(pos)

    def smtp_server(self, event):
        """Limit smtp server address to 50 characters"""
        self.apply_button.Enable(True)
        self.cancel_button.Enable(True)
        self.test_button.Enable(False)
        text = event.GetString()
        if len(text)>50:
            pos=self.smtp_server_field.GetInsertionPoint()
            self.smtp_server_field.Remove(50,len(text)+1)
            self.smtp_server_field.SetInsertionPoint(pos)

    # Button binding methods

    def apply_button_pressed(self, event):
        """ Apply button - check and apply all fields"""
        self.apply_button.Enable(False)
        #
        # Enable Email alerts
        if self.email_enable_field.GetValue():
            net_cfg["EMAIL_ENABLED"]="1"
        else:
            net_cfg["EMAIL_ENABLED"]="0"
        #
        # Email max rate
        text=self.email_max_rate_field.GetValue()
        text=str(text).strip()
        if validate.is_text_integer(text, 1, 300):
            net_cfg["EMAIL_MAX_RATE"]=text
        else:
            wx.MessageBox("The Email maximum rate must be between 1 and 300",
                           caption="ERROR",
                           style=wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP)
            self.email_max_rate_field.SetValue(net_cfg["EMAIL_MAX_RATE"])
        #
        # Email source
        text=self.email_source_address_field.GetValue()
        text=str(text).strip()
        if validate.check_mail_address(text):
            net_cfg["EMAIL_SOURCE"]=text
        else:
            wx.MessageBox("The Email Source address is formatted incorrectly",
                           caption="ERROR",
                           style=wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP)
            self.email_source_address_field.SetValue(net_cfg["EMAIL_SOURCE"])
        #
        # Email destination
        text=self.email_destination_address_field.GetValue()
        text=str(text).strip()
        if validate.check_mail_address_list(text):
            net_cfg["EMAIL_DESTINATION"]=text
        else:
            wx.MessageBox("The Email destination addresses are formatted incorrectly",
                           caption="ERROR",
                           style=wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP)
            self.email_destination_address_field.SetValue(net_cfg["EMAIL_DESTINATION"])
        #
        # Email subject
        text=self.email_subject_field.GetValue()
        text=str(text).strip()
        net_cfg["EMAIL_SUBJECT"]=text
        #
        #
        # SMTP Server
        text=self.smtp_server_field.GetValue()
        text=str(text).strip()
        if validate.check_part_address(text):
            # So address format is ok
            net_cfg["SMTP_SERVER"]=text
             # Check SMTP server name resolves correctly
            try:
                socket.gethostbyname(text)
            except:
                wx.MessageBox("The SMTP server name cannot be resolved",
                               caption="ERROR",
                               style=wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP)
        else:
            wx.MessageBox("The SMTP server is formatted incorrectly",
                           caption="ERROR",
                           style=wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP)
            self.smtp_server_field.SetValue(net_cfg["SMTP_SERVER"])
        #
        # Save config file to disc
        if not writeconfigtofile():
            wx.MessageBox("ERROR: Unable to save changes to disk",
                           caption="ERROR",
                           style=wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP)
        #
        # Only enable the test button if the global enable email checkbox is ticked
        if net_cfg["EMAIL_ENABLED"]=="0":
            self.test_button.Enable(False)
            self.results_box.SetLabel("Emails are disabled, until the Global enable email checkbox is ticked - and the Apply button pressed.")
        else:
            self.test_button.Enable(True)
            self.results_box.SetLabel("On pressing Test, an email will be sent")
        # As Apply has been pressed, disable the Apply and Cancel buttons
        self.apply_button.Enable(False)
        self.cancel_button.Enable(False)

    def cancel_button_pressed(self, event):
        """ Cancel button - set email fields back to original values"""
        #
        if net_cfg["EMAIL_ENABLED"]=="0":
            self.email_enable_field.SetValue(0)
        else:
            self.email_enable_field.SetValue(1)
        #
        self.email_max_rate_field.SetValue(net_cfg["EMAIL_MAX_RATE"])
        #
        self.email_source_address_field.SetValue(net_cfg["EMAIL_SOURCE"])
        #
        self.email_destination_address_field.SetValue(net_cfg["EMAIL_DESTINATION"])
        #
        self.email_subject_field.SetValue(net_cfg["EMAIL_SUBJECT"])
        #
        self.smtp_server_field.SetValue(net_cfg["SMTP_SERVER"])
        #
        # Only enable the test button if the global enable email checkbox is ticked
        if net_cfg["EMAIL_ENABLED"]=="0":
            self.test_button.Enable(False)
            self.results_box.SetLabel("Emails are disabled, until the Global enable email checkbox is ticked - and the Apply button pressed.")
        else:
            self.test_button.Enable(True)
            self.results_box.SetLabel("On pressing Test, an email will be sent")
        # Disable the Apply and Cancel buttons
        self.apply_button.Enable(False)
        self.cancel_button.Enable(False)

    def test_button_pressed(self, event):
        """Test button - send an email and report any errors"""
        # Create the email to send
        self.results_box.SetLabel("Sending From: "+net_cfg["EMAIL_SOURCE"]+ "\nTo: "+net_cfg["EMAIL_DESTINATION"] + "\nPlease wait...")
        try:
            socket.gethostbyname(net_cfg["SMTP_SERVER"])
        except:
            self.results_box.SetLabel("Email not sent, SMTP server name cannot be resolved")
            return
        # wait one second then call self.send_test_email
        wx.FutureCall(1000, self.send_test_email)

    def send_test_email(self):
        """Sends a test email, and puts results into self.results_box"""
        # Create the email to send
        header_text="From: "+net_cfg["EMAIL_SOURCE"]+"\r\n"
        header_text+="To: "+net_cfg["EMAIL_DESTINATION"]+"\r\n"
        header_text+="Subject: "+net_cfg["EMAIL_SUBJECT"]+"\r\n\r\n"
        header_text+="Test Message from Skipole Monitor : "+time.asctime()+"\r\n\r\n"
        # Create a list of addresses to send the alert to
        address_list=net_cfg["EMAIL_DESTINATION"].split(";")
        #
        # And send the mail
        try:
            outbox=smtplib.SMTP(net_cfg["SMTP_SERVER"])
            outbox.sendmail(net_cfg["EMAIL_SOURCE"], address_list, header_text)
            outbox.quit()
        except smtplib.SMTPResponseException, var:
            self.results_box.SetLabel("An Error occurred\nSMPT Error code : " + str(var[0]) + "\nSMTP Error message : " + var[1])
        except:
            self.results_box.SetLabel("Error : no information available")
        else:
            self.results_box.SetLabel("Email sent: You should check to see if the email was received.")
        return


